
#include "date.h"

static uint8_t is_leap_year(uint16_t y)
{
	if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){
		return 1;
	}
	else{
		return 0;
	}
}

/*
 31	 : 1 3 5 7 8 10 12
 30	 : 4 6 9 11
 28/29: 2
 */
static uint8_t how_many_days(uint16_t year, uint8_t month)
{
	uint8_t day = 0;

	if ((month <= 12) && (month > 0)) {
		if (month % 2 == 0x00) {
			// 2-4-6-8-10-12

			if (month >= 8) {
				day = 31;
			} else if (month != 2) {
				day = 30;
			} else {
				// month == 2
				day = 28;
				if (is_leap_year(year)) {
					day = 29;
				}
			}
		} else {
			// 1-3-5-7-9-11
			if (month >= 9) {
				day = 30;
			} else {
				day = 31;
			}
		}
	}
	return day;
}

//retur 1-7,err 0
static uint8_t caculate_weekday(uint16_t year, uint8_t month, uint8_t day)
{
	uint16_t y;
	uint8_t m;
	uint8_t d;
	uint8_t w;

	y = year;
	m = month;
	d = day;

	if (m == 1 || m == 2) {
		m += 12;
		y--;
	}
	w = (d + 1 + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;

	if (w == 0) {
		w = 7;
	}

	return w;
}

//static uint8_t add_weekday(uint8_t old_weekday, uint8_t add_weekdays)
//{
//	old_weekday += add_weekdays;
//	if(old_weekday > 7){
//		old_weekday = old_weekday % 7;
//	}
//	return old_weekday;
//}

//static uint32_t caculate_days(DATE_STRUCT date_start, DATE_STRUCT date_end)
//{
//	uint32_t i = 0;
//
//	while(1){
//		date_start.day++;
//		if(date_start.day > how_many_days(date_start.year, date_start.month)){
//			date_start.day = 1;
//			date_start.month++;
//			if(date_start.month > 12){
//				date_start.month = 1;
//				date_start.year++;
//			}
//		}
//		i++;
//		if((date_start.year == date_end.year)&&
//		(date_start.month == date_end.month)&&
//		(date_start.day == date_end.day)){
//			break;
//		}
//	}
//	return i;
//}
//
//static DATE_STRUCT backword_days(DATE_STRUCT date_end, uint32_t days)
//{
//	uint32_t i = days;
//
//	while(1){
//		date_end.day--;
//		if(date_end.day <= 0){
//			date_end.month--;
//			if(date_end.month <= 0){
//				date_end.month = 12;
//				date_end.year--;
//			}
//			date_end.day = how_many_days(date_end.year, date_end.month);
//		}
//		i--;
//		if(i == 0){
//			break;
//		}
//	}
//	return date_end;
//}

static uint8_t date_chack_legal(DATE_STRUCT date)
{
	if((date.month < 1)||(date.month > 12)){
		return 0;
	}

	if((date.day < 1)||(date.day > how_many_days(date.year, date.month))){
		return 0;
	}
	
	if((date.weekday < 1)||(date.weekday > 7)){
		return 0;
	}
	return 1;	
}

/*******************************************************************************/
/*
void date_print(DATE_STRUCT date)
{
	printf_string("date: ");
	printf_byte_decimal(date.year);
	printf_char('/');
	printf_byte_decimal(date.month);
	printf_char('/');
	printf_byte_decimal(date.day);
	printf_string("\t wday: ");
	printf_byte_decimal(date.weekday);
	printf_string("\r\n");
}
*/

uint8_t date_init(DATE_STRUCT* date,\
				uint16_t year, uint8_t month, uint8_t day)
{
	DATE_STRUCT temp_date;
		
	temp_date.year = year;
	temp_date.month = month;
	temp_date.day = day;
	temp_date.weekday = 1;
	
	if(0 != date_chack_legal(temp_date)){
		temp_date.weekday = caculate_weekday(year, month, day);
		*date = temp_date;
		return 1;
	}
	else{
		return 0;
	}	
}

uint8_t date_add_one_day(DATE_STRUCT* date)
{

	if(0 == date_chack_legal(*date)){
		return 0;
	}
	
	date->day++;
	if(date->day > how_many_days(date->year, date->month)){
		date->day = 1;
		date->month++;
		if(date->month > 12){
			date->month = 1;
			date->year++;
		}
	}
	date->weekday++;
	if(date->weekday > 7){
		date->weekday = 1;
	}
	
	return 1;
}

/*uint8_t date_add_years(DATE_STRUCT* date, uint8_t year)
{
	uint8_t old_year = date->year;
	
	if(0 == date_chack_legal(*date)){
		return 0;
	}
	
	date->year += year;
	if(date->month == 2){
		if((is_leap_year(old_year + 2000) == 1)&&(date->day == 29)){
			if(is_leap_year(date->year + 2000) != 1){
				date->day = 28;
			}
		}
		if((is_leap_year(old_year + 2000) != 1)&&(date->day == 28)){
			if(is_leap_year(date->year + 2000) == 1){
				date->day = 29;
			}		
		}
	}
	date->weekday = caculate_weekday(date->year, date->month, date->day);
	
	return 1;
}



uint8_t date_add_months(DATE_STRUCT* date, uint8_t month)
{
//	uint8_t old_year = date->year;
//	uint8_t old_month = date->month;
	uint8_t temp_day = 0;
			
	if(0 == date_chack_legal(*date)){
		return 0;
	}
	
	date->year += (month / 12);
	date->month = (((date->month-1)+month)%12) + 1;

//1	
	temp_day = how_many_days(date->year, date->month);
	if(date->day >= temp_day){
		date->day = temp_day;
	}
	
//2	
//if current day is the last day in the mounth
//when the mounth changed, the day will the last day in the new mounth also
//	if(date->day == how_many_days(old_year, old_month)){
//		date->day = how_many_days(date->year, date->month);
//	}

	date->weekday = caculate_weekday(date->year, date->month, date->day);
					
	return 1;
}

uint8_t date_add_days(DATE_STRUCT* date, uint8_t day)
{
	uint8_t all_days = 0;
	uint8_t add_days = 0;
	uint8_t old_weekday = date->weekday;
			
	if(0 == date_chack_legal(*date)){
		return 0;
	}
	
	add_days = date->day + day;
	while(1){
		all_days = how_many_days(date->year, date->month);	
		if(add_days > all_days) {
			add_days -= all_days;
			date->month++;
			if(date->month > 12){
				date->month  = 1;
				date->year++;
			}
		}
		else{
			break;
		}			
	}
	date->day = add_days;
	
	date->weekday = caculate_weekday(date->year, date->month, date->day);	
	
	return 1;
}*/



//uint32_t date_caculate_days(DATE_STRUCT date_start, DATE_STRUCT date_end)
//{
//	if(0 == date_chack_legal(date_start)){
//		return 0;
//	}
//	if(0 == date_chack_legal(date_end)){
//		return 0;
//	}
//
//	if(date_start.year > date_end.year){
//		return 0;
//	}
//	if(date_start.year == date_end.year){
//		if(date_start.month > date_end.month){
//			return 0;
//		}
//		if(date_start.month == date_end.month){
//			if(date_start.day >= date_end.day){
//				return 0;
//			}
//		}
//	}
//
//	return caculate_days(date_start, date_end);
//}

//uint8_t date_backword_days(DATE_STRUCT* date_start, DATE_STRUCT date_end, uint32_t days)
//{
//
//	if(0 == date_chack_legal(date_end)){
//		return 0;
//	}
//
//	*date_start = backword_days(date_end, days);
//	date_start->weekday = caculate_weekday(date_start->year, date_start->month, date_start->day);
//
//	return 1;
//}


/******************************************************************************/
//e.g.
//void test(void)
//{
//
//	DATE_STRUCT start;
//	DATE_STRUCT end;
//
//	uint32_t days = 0;
//
//	date_init(&start, 15, 6, 5);
//	date_init(&end, 15, 8, 10);
//	date_print(start);
//	date_print(end);
//
//	days = date_caculate_days(start, end);
//	printf("days: %d\r\n",days);
//
//	date_backword_days(&start, end, 66);
//	date_print(start);
//}


//int data formate XXYYMMDD 
//e.g. 000F0710 -> 	0F:15y 
//					07:7m 
//					10:17d 
//uint8_t int_to_date(DATE_STRUCT* retun_date, uint32_t int_date)
//{
//	DATE_STRUCT temp_date;
//
//	temp_date.year = (uint8_t)(int_date>>16)&0x000000ff;
//	temp_date.month = (uint8_t)(int_date>>8)&0x000000ff;
//	temp_date.day = (uint8_t)(int_date)&0x000000ff;
//
//	if(0 != date_chack_legal(temp_date)){
//		*retun_date = temp_date;
//		return 1;
//	}
//	else{
//		return 0;
//	}
//}
//
//uint8_t date_to_int(DATE_STRUCT date, uint32_t* return_int)
//{
//
//	if(0 == date_chack_legal(date)){
//		return 0;
//	}
//
//	*return_int =	(date.year << 16)|
//					(date.month << 8)|
//					(date.day);
//	return 1;
//}
